package org.faster.dal.descriptor.db.impl;


import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.faster.dal.cache.CacheManager;
import org.faster.dal.descriptor.Column;
import org.faster.dal.descriptor.Table;
import org.faster.dal.descriptor.db.ResolveDataBase;
import org.faster.dal.descriptor.resolver.FieldSqlGenerator;
import org.faster.dal.internal.util.message.Messages;
import org.faster.dal.logging.Log;
import org.faster.dal.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class SimpleResolveDatabase implements ResolveDataBase{
    
    private static final Log LOG = LogFactory.getLog(SimpleResolveDatabase.class);
    
    private static final ConcurrentMap<Object, Object> cache = new ConcurrentHashMap<Object, Object>();
    
    @Autowired(required=false)
    private FieldSqlGenerator fieldSqlGenerator;
    
    @Autowired
    private CacheManager cacheManager;
    
    @Autowired
    private DataSource dataSource;
    
    private DatabaseMetaData databaseMetaData;
    

    /**
     * @param databaseMetaData
     * @param model
     * @param primaryKey
     * @param name
     * @throws SQLException
     */
    public Table loadTable(String tableName){
        Table t = null;
        if(cache.containsKey(tableName)){
            t = (Table)cache.get(tableName);
        }else{
            if(cacheManager != null){
                t = (Table) cacheManager.getCache().getObject(tableName);
            }
        }
        if(t != null){
            return t;
        }
        
        Table table = new Table();
        boolean tableExist = false;
        ResultSet pkRS = null;
        ResultSet columnsRS = null;
        try {
            if(databaseMetaData == null){
                databaseMetaData = dataSource.getConnection().getMetaData();
            }
            //primary keys
            pkRS = databaseMetaData.getPrimaryKeys(null, null,tableName);
            while (pkRS.next()) {
                String columnName = pkRS.getString("COLUMN_NAME");
                table.addPrimaryFieldName(columnName);
                tableExist = true;
            }
            
            //columns
            columnsRS = databaseMetaData.getColumns(null, null, tableName, null);
            while (columnsRS.next()) {
                Column field = new Column();
                field.setJdbcType(columnsRS.getInt("DATA_TYPE"));
                field.setFieldName(columnsRS.getString("COLUMN_NAME"));
                if(StringUtils.isNotEmpty(columnsRS.getString("REMARKS"))){
                    field.setName(columnsRS.getString("REMARKS"));
                }
                if(fieldSqlGenerator != null){
                    field.setFieldSql(fieldSqlGenerator.buildSingleSql(field));
                }
                if(table.getPrimaryKey().getFields().contains(field.getFieldName())){
                    field.setPrimaryKey(true);
                }
                table.addField(field);
                tableExist = true;
            }
        } catch (SQLException e) {
            LOG.error(Messages.getString("RuntimeError.2"), e);
        } finally {
            closeResultSet(pkRS);
            closeResultSet(columnsRS);
        }
        
        if(tableExist){
            table.setTableName(tableName);
            table.caculationAllColumn();
            cache.put(tableName, table);
            if(cacheManager != null){
                cacheManager.getCache().putObject(tableName, table);
            }
            return table;
        }else{
            return null;
        }
    }
    
    
    @Override
    public Table reloadTable(String tableName) {
        cache.remove(tableName);
        if(cacheManager != null){
            cacheManager.getCache().removeObject(tableName);
        }
        return loadTable(tableName);
    }
    

    private void closeResultSet(ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // ignore
                ;
            }
        }
    }


    public void setFieldSqlGenerator(FieldSqlGenerator fieldSqlGenerator) {
        this.fieldSqlGenerator = fieldSqlGenerator;
    }


    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }


    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    

    

    

}
